<script lang="jsx" setup>
import { ref, watch } from 'vue';
import { useAntdForm } from '@/hooks/common/form';
import Dictionary from './dictionary.vue';

const props = defineProps({
  isSearch: {
    type: Boolean,
    default: () => false
  },
  /**
   * formList 格式
   *
   * type 表单类型 searchInput input inputNumber select radio datePicker dateRangePicker dictionary
   *
   * key 字段名
   *
   * defaultValue 默认值
   *
   * label 标签名称
   *
   * rule 效验规则
   *
   * className 控件类名
   *
   * ref ref
   *
   * textareaRows 多行文本行数
   *
   * maxlength 多行文本最大输入长度
   *
   * placeholder 输入框提示信息
   *
   * selectOptions select、radio 选项配置
   *
   * clear 是否可清除输入框 默认支持
   *
   * search select是否支持搜索 默认支持
   *
   * rowOptions 响应式配置
   *
   * rowOptions.span 占比 默认为24 占满全行
   *
   * rowOptions.xs <576px 响应式栅格，可为栅格数 默认为null
   *
   * rowOptions.sm ≥576px 响应式栅格，可为栅格数 默认为null
   *
   * rowOptions.md ≥768px 响应式栅格，可为栅格数 默认为null
   *
   * rowOptions.lg ≥992px 响应式栅格，可为栅格数 默认为null
   *
   * rowOptions.xl ≥1200px 响应式栅格，可为栅格数 默认为null
   *
   * rowOptions.xxl ≥1600px 响应式栅格，可为栅格数 默认为null
   *
   * rowOptions.colClass clo的类名
   *
   * hidden 是否隐藏
   */
  // 表单列表
  formList: {
    type: Array,
    default: () => []
  },
  // ROW 间隔
  gutter: {
    type: [Number, Object, Array],
    default: () => 20
  },
  // rowClass
  gutterClass: {
    type: String,
    default: () => ''
  }
});

const formList = ref(props.formList);

const formVal = defineModel('model', { required: false, type: Object });
const { formRef, validate } = useAntdForm();

const emit = defineEmits(['search', 'reset']);

const rules = ref(initFormRules());

const activeKey = '1';

function initFormRules() {
  const rulesObj = {};
  formList.value.forEach(item => {
    if (item.rule) {
      rulesObj[item.key] = item.rule;
    }
  });
  return rulesObj;
}

function search() {
  emit('search', formVal.value);
}

async function validateForm() {
  await validate();
}

function reset() {
  Object.keys(formVal.value).forEach(item => {
    formVal.value[item] = null;
  });
  emit('reset', formVal.value);
}

watch(
  () => props.formList,
  val => {
    formList.value = val;
    rules.value = initFormRules();
  },
  {
    deep: true
  }
);

defineExpose({
  formVal,
  reset,
  validateForm
});
</script>

<template>
  <AForm
    ref="formRef"
    :model="model"
    class="my-from jl-form"
    :label-col="{ lg: 8, xs: 4 }"
    label-wrap
    :class="props.isSearch ? 'search-form' : 'other-form'"
    :rules="rules"
  >
    <ARow :gutter="props.gutter || 20" :class="props.gutterClass">
      <template v-for="item in formList" :key="item.key">
        <template v-if="!(item.span === 0 || item?.span?.value === 0)">
          <ACol
            v-show="!item.hidden"
            :span="item.span?.value ? item.span?.value : item.span ? item.span : 24"
            :xs="item.xs || null"
            :sm="item.sm || null"
            :lg="item.lg || null"
            :xl="item.xl || null"
            :xxl="item.xxl || null"
            :class="item.colClass"
          >
            <template v-if="item.type === 'customRender' && item.customRender">
              <component :is="item.customRender"></component>
            </template>
            <template v-else-if="item.type === 'tabs'">
              <ATabs v-model:activeKey="activeKey">
                <ATabPane key="1" :tab="item.name"></ATabPane>
              </ATabs>
            </template>
            <AFormItem v-else :name="item.key" :label="item.label" :label-col="{}">
              <template v-if="item.labelSlot" #label>
                <component :is="item.labelSlot"></component>
              </template>

              <template v-if="(item.type.value || item.type) == 'searchInput'">
                <AInputSearch
                  v-model:value="formVal[item.key]"
                  :placeholder="item.placeholder || ''"
                  :allow-clear="item.clear"
                  autocomplete="off"
                  :disabled="item.disabled?.value ? item.disabled.value : item.disabled"
                  :readonly="item.readonly"
                  :class="item.className"
                  :enter-button="item.searchBtnText || '查询'"
                  class="min-form-control"
                  @search="
                    e => {
                      item.handleSearch && item.handleSearch(e, formVal[item.key], formVal);
                    }
                  "
                />
              </template>

              <template v-if="(item.type.value || item.type) == 'inputPassword'">
                <AInputPassword
                  v-model:value="formVal[item.key]"
                  :placeholder="item.placeholder || ''"
                  autocomplete="off"
                  :disabled="item.disabled?.value ? item.disabled.value : item.disabled"
                  :readonly="item.readonly"
                  :class="item.className"
                  class="min-form-control"
                  @change="
                    e => {
                      item.change && item.change(e, formVal[item.key], formVal);
                    }
                  "
                  @blur="
                    e => {
                      item.blur && item.blur(e, formVal[item.key], formVal);
                    }
                  "
                />
              </template>

              <template v-if="(item.type.value || item.type) == 'input'">
                <AInput
                  v-model:value="formVal[item.key]"
                  :placeholder="item.placeholder || ''"
                  :allow-clear="item.clear"
                  autocomplete="off"
                  :disabled="item.disabled?.value ? item.disabled.value : item.disabled"
                  :readonly="item.readonly"
                  :class="item.className"
                  :prefix="item.prefix"
                  :suffix="item.suffix"
                  :maxlength="item.maxlength"
                  class="min-form-control w-full"
                  @change="
                    e => {
                      item.change && item.change(e, formVal[item.key], formVal);
                    }
                  "
                  @keypress.enter="
                    e => {
                      if (props.isSearch) {
                        search();
                      }
                      item.keypressEnter && item.keypressEnter(e, formVal[item.key], formVal);
                    }
                  "
                  @keypress="
                    e => {
                      item.keypress && item.keypress(e, formVal[item.key], formVal);
                    }
                  "
                  @blur="
                    e => {
                      item.blur && item.blur(e, formVal[item.key], formVal);
                    }
                  "
                  @click="
                    e => {
                      item.click && item.click(e, formVal[item.key], formVal);
                    }
                  "
                >
                  <template v-if="item.prefixSlot" #prefix>
                    <component :is="item.prefixSlot"></component>
                  </template>
                  <template v-if="item.suffixSlot" #suffix>
                    <component :is="item.suffixSlot"></component>
                  </template>
                </AInput>
              </template>

              <template v-if="(item.type.value || item.type) == 'inputSelect'">
                <AInput
                  v-model:value="formVal[item.key]"
                  :placeholder="item.placeholder || ''"
                  :allow-clear="item.clear"
                  autocomplete="off"
                  :disabled="item.disabled?.value ? item.disabled.value : item.disabled"
                  :readonly="item.readonly"
                  :class="item.className"
                  :prefix="item.prefix"
                  :maxlength="item.maxlength"
                  class="min-form-control my-input-select w-full"
                  @change="
                    e => {
                      item.change && item.change(e, formVal[item.key], formVal);
                    }
                  "
                  @keypress.enter="
                    e => {
                      if (props.isSearch) {
                        search();
                      }
                      item.keypressEnter && item.keypressEnter(e, formVal[item.key], formVal);
                    }
                  "
                  @keypress="
                    e => {
                      item.keypress && item.keypress(e, formVal[item.key], formVal);
                    }
                  "
                  @blur="
                    e => {
                      item.blur && item.blur(e, formVal[item.key], formVal);
                    }
                  "
                >
                  <template #addonAfter>
                    <ASelect
                      v-model:value="formVal[item.key]"
                      placeholder="请选择"
                      :disabled="item.disabled?.value ? item.disabled.value : item.disabled"
                      :readonly="item.readonly"
                      :style="{ width: item.selectWidth || '100px' }"
                    >
                      <ASelectOption
                        v-for="o in item.selectOptions.value || item.selectOptions"
                        :key="o.value"
                        :value="o.value"
                        :disabled="o.disabled"
                      >
                        {{ o.label }}
                      </ASelectOption>
                    </ASelect>
                  </template>
                </AInput>
              </template>

              <template v-if="(item.type.value || item.type) == 'textarea'">
                <ATextarea
                  v-model:value="formVal[item.key]"
                  :placeholder="item.placeholder || ``"
                  :allow-clear="item.clear"
                  autocomplete="off"
                  :disabled="item.disabled?.value ? item.disabled.value : item.disabled"
                  :readonly="item.readonly"
                  :class="item.className"
                  :rows="item.textareaRows"
                  :maxlength="item.maxlength"
                  class="w-full"
                  @change="
                    e => {
                      item.change && item.change(e, formVal[item.key], formVal);
                    }
                  "
                  @keypress.enter="
                    e => {
                      if (props.isSearch) {
                        search();
                      }
                      item.keypressEnter && item.keypressEnter(e, formVal[item.key], formVal);
                    }
                  "
                  @keypress="
                    e => {
                      item.keypress && item.keypress(e, formVal[item.key], formVal);
                    }
                  "
                  @blur="
                    e => {
                      item.blur && item.blur(e, formVal[item.key], formVal);
                    }
                  "
                ></ATextarea>
              </template>
              <template v-if="(item.type.value || item.type) == 'inputNumber'">
                <AInputNumber
                  v-model:value="formVal[item.key]"
                  :placeholder="item.placeholder || `请输入${item.label}`"
                  :allow-clear="item.clear"
                  autocomplete="off"
                  :disabled="item.disabled?.value ? item.disabled.value : item.disabled"
                  :readonly="item.readonly"
                  :class="item.className"
                  :prefix="item.prefix"
                  class="min-form-control w-full"
                  @change="
                    e => {
                      item.change && item.change(e, formVal[item.key], formVal);
                    }
                  "
                  @keypress.enter="
                    e => {
                      if (props.isSearch) {
                        search();
                      }
                      item.keypressEnter && item.keypressEnter(e, formVal[item.key], formVal);
                    }
                  "
                  @keypress="
                    e => {
                      item.keypress && item.keypress(e, formVal[item.key], formVal);
                    }
                  "
                  @blur="
                    e => {
                      item.blur && item.blur(e, formVal[item.key], formVal);
                    }
                  "
                ></AInputNumber>
              </template>
              <template v-if="(item.type.value || item.type) == 'select'">
                <div class="flex">
                  <ASelect
                    v-model:value="formVal[item.key]"
                    :placeholder="item.placeholder || ``"
                    :show-search="item.search"
                    :allow-clear="item.clear"
                    :disabled="item.disabled?.value ? item.disabled.value : item.disabled"
                    :mode="item.selectMode"
                    :max-tag-count="item.maxTagCount"
                    class="min-form-control"
                    @change="
                      e => {
                        item.change && item.change(e, formVal[item.key], formVal);
                      }
                    "
                  >
                    <ASelectOption
                      v-for="o in item.selectOptions.value || item.selectOptions"
                      :key="o.value"
                      :value="o.value"
                      :disabled="o.disabled"
                    >
                      {{ o.label }}
                    </ASelectOption>
                  </ASelect>
                  <template v-if="item.showSelectOtherBtn">
                    <AButton
                      class="mini-btn"
                      :class="item.selectOtherBtnClassName"
                      type="primary"
                      :disabled="item.disabled?.value ? item.disabled.value : item.disabled"
                      @click="
                        () => {
                          item.handleSelectOtherBtnClick && item.handleSelectOtherBtnClick();
                        }
                      "
                    >
                      {{ item.selectOtherBtnText }}
                    </AButton>
                  </template>
                </div>
              </template>
              <template v-if="(item.type.value || item.type) == 'radio'">
                <ARadioGroup
                  v-model:value="formVal[item.key]"
                  :disabled="item.disabled?.value ? item.disabled.value : item.disabled"
                  :class="item.className"
                  @change="
                    e => {
                      item.change && item.change(e, formVal[item.key], formVal);
                    }
                  "
                >
                  <template v-if="item.radioType === 'button'">
                    <ARadioButton
                      v-for="o in item.selectOptions.value || item.selectOptions"
                      :key="o.value"
                      :value="o.value"
                      :disabled="o.disabled"
                    >
                      {{ o.label }}
                    </ARadioButton>
                  </template>
                  <template v-else>
                    <ARadio
                      v-for="o in item.selectOptions.value || item.selectOptions"
                      :key="o.value"
                      :value="o.value"
                      :disabled="item.disabled?.value ? item.disabled.value : item.disabled"
                    >
                      {{ o.label }}
                    </ARadio>
                  </template>

                  <template v-if="item.showReset">
                    <AButton
                      type="primary"
                      ghost
                      class="mini-btn"
                      :disabled="item.disabled?.value ? item.disabled.value : item.disabled"
                      @click="formVal[item.key] = ''"
                    >
                      重置
                    </AButton>
                  </template>
                </ARadioGroup>
              </template>

              <template v-if="(item.type.value || item.type) == 'checkbox'">
                <ACheckboxGroup
                  v-model:value="formVal[item.key]"
                  :options="item.selectOptions.value || item.selectOptions"
                  :disabled="item.disabled?.value ? item.disabled.value : item.disabled"
                  @change="
                    e => {
                      item.change && item.change(e, formVal[item.key], formVal);
                    }
                  "
                ></ACheckboxGroup>
              </template>
              <template v-if="(item.type.value || item.type) == 'datePicker'">
                <ADatePicker
                  v-model:value="formVal[item.key]"
                  :picker="item.picker"
                  :allow-clear="item.clear"
                  :show-time="item.showTime"
                  :disabled="item.disabled?.value ? item.disabled.value : item.disabled"
                  :placeholder="item.placeholder || ``"
                  :format="item.format || (item.showTime ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD')"
                  :value-format="item.valueFormat || (item.showTime ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD')"
                  class="min-form-control w-full"
                  @change="
                    e => {
                      item.change && item.change(e, formVal[item.key], formVal);
                    }
                  "
                ></ADatePicker>
              </template>
              <template v-if="(item.type.value || item.type) == 'dateRangePicker'">
                <ARangePicker
                  v-model:value="formVal[item.key]"
                  :picker="item.picker"
                  :allow-clear="item.clear"
                  :disabled="item.disabled?.value ? item.disabled.value : item.disabled"
                  :format="item.format || (item.showTime ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD')"
                  :value-format="item.valueFormat || (item.showTime ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD')"
                  :show-time="item.showTime"
                  class="min-form-control w-full"
                  @change="
                    e => {
                      item.change && item.change(e, formVal[item.key], formVal);
                    }
                  "
                />
              </template>
              <template v-if="(item.type.value || item.type) == 'timePicker'">
                <ATimePicker
                  v-model:value="formVal[item.key]"
                  :picker="item.picker"
                  :allow-clear="item.clear"
                  :disabled="item.disabled?.value ? item.disabled.value : item.disabled"
                  :value-format="item.showSeconds ? 'HH:mm:ss' : 'HH:mm'"
                  :format="item.showSeconds ? 'HH:mm:ss' : 'HH:mm'"
                  :show-time="item.showTime"
                  class="min-form-control w-full"
                  @change="
                    e => {
                      item.change && item.change(e, formVal[item.key], formVal);
                    }
                  "
                />
              </template>
              <template v-if="(item.type.value || item.type) == 'dictionary'">
                <Dictionary
                  v-model:value="formVal[item.key]"
                  v-bind="item"
                  @change="
                    e => {
                      item.change && item.change(e, formVal[item.key], formVal);
                    }
                  "
                ></Dictionary>
              </template>
            </AFormItem>
          </ACol>
        </template>
      </template>
      <slot name="search">
        <div class="flex">
          <AFormItem class="m-0">
            <div class="w-full flex-y-center justify-end gap-12px">
              <template v-if="props.isSearch">
                <AButton type="primary" ghost class="mini-btn" @click="search">
                  <template #icon>
                    <icon-ic-round-search class="align-sub text-icon" />
                  </template>
                  <span class="ml-3px">搜索</span>
                </AButton>

                <AButton class="mini-btn" @click="reset">
                  <template #icon>
                    <icon-ic-round-refresh class="align-sub text-icon" />
                  </template>
                  <span class="ml-3px">重置</span>
                </AButton>
              </template>
              <slot name="other"></slot>
            </div>
          </AFormItem>
        </div>
      </slot>
    </ARow>
  </AForm>
</template>

<style lang="scss" scoped>
.other-form {
  :deep(.ant-form-item) {
    margin-bottom: 5px;
  }
}

.search-form {
  :deep(.ant-form-item) {
    margin-bottom: 0;
  }
}
.my-input-select {
  :deep(.ant-input-group-addon) {
    height: 20px !important;
    line-height: 20px;
  }
}
</style>
